#define MSIPROUTE_C
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <net/route.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>

#include <netdb.h>
//set start flag
#include <libmscommon/mscommon.h>
#include <libmscommon/msstring.h>
#include <libmscommon/msnetwork.h>
#include <libmscommon/msthread.h>
#include <libmscommon/mscjson.h>
#include <libmscommon/msmd.h>
#include <libmslog/mslog.h>
#include "msperformance.h"
#include "msiproute.h"
#include "mspppoe.h"

#define FLAG "IPROUTE"

#define ms_dbroute    				"/etc/mscore/db/msdb_iproute.db"
#define msiproute_rttables			"/etc/iproute2/rt_tables"
#define msiproute_font_style 		"style=\"color:black;\""
#define enable_pppoe_router		ms_false
typedef struct IPROUTEContext{
	ms_byte  tablename[64];
	ms_u32   tableid;
	ms_byte ifacename[128];
	ms_byte gateway[128];
	ms_byte netmaskbit[128];
	ms_byte ipaddress[128];
	ms_bool need_restart;
}IPROUTEContext;
typedef struct IPROUTEInfo{
	ms_bool enable;
	ms_bool init;
	ms_u08 usrtable_num;
	ms_u08 table_num;		//usrtable_num+3
	IPROUTEContext iproute_ctt[msnet_maxnum_iface+3];
}IPROUTEInfo;

static IPROUTEInfo iproute_info;
static NETCARDInfo*pnetcard_info=&hardware_info.netcard_info;


ms_void msiproute_innerapi_tableShow(ms_string ptable)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	//ip route show table tab_em1
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip route show table  %s",ptable);
	ms_verbose("%s",cmdbuf);
}

ms_void msiproute_innerapi_tableAddDefault(ms_string tablename,ms_string ifacename,ms_string gateway)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	//ip route add default dev em1 via 192.168.200.82  table tab_em1
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip route add default dev %s   via %s table %s", ifacename,gateway,tablename);	
	ms_verbose("%s",cmdbuf);
}

ms_void msiproute_innerapi_tableAdd(ms_string tablename,ms_string ifacename,ms_string ipaddress,ms_string netmaskbit)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	//ip route add 192.168.202.0/24 dev em1 scope link src 192.168.0.245  table tab_em1
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip route add %s dev %s   src %s table %s", netmaskbit,ifacename,ipaddress,tablename);
	ms_verbose("%s",cmdbuf);
}
ms_void msiproute_innerapi_tableDel(ms_string tableitem,ms_string tablename)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	//ip route del 192.168.202.0/24 dev em1 scope link src 192.168.0.245 table tab_em1
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip route del %s table %s", tableitem,tablename);
	ms_verbose("%s",cmdbuf);
}
ms_void msiproute_innerapi_IPVersion(ms_void)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	ms_system("ip -V");
}
ms_void msiproute_innnerapi_ruleDel_byTableName(ms_string ptable)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	//ip rule del lookup tab_em1
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip rule del lookup %s",ptable);
	ms_verbose("%s",cmdbuf);
}
ms_void msiproute_innnerapi_ruleDel(ms_string rule)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip rule del  %s",rule);
	ms_verbose("%s",cmdbuf);
}
ms_void msiproute_innnerapi_ruleAdd_bySrc(ms_string psrcip,ms_string ptable)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	/*ip rule add from 192.168.200.244    table tab_em1  	
	     ip rule add from 192.168.200.0/24 table tab_em1 */
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip rule add from %s table %s", psrcip,ptable);
	ms_verbose("%s",cmdbuf);
}
ms_void msiproute_innnerapi_ruleAddAll(ms_string ptable)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	/*ip rule add from all   table tab_em1 */
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip rule add from all table %s",ptable);
	ms_verbose("%s",cmdbuf);
}
ms_void msiproute_innnerapi_ruleAdd_byDest(ms_string pdestip,ms_string ptable)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	/*ip rule add to 192.168.200.244    table tab_em1  	
	     ip rule add to 192.168.200.0/24 table tab_em1 */
	ms_byte cmdbuf[256]={0};
	ms_cmd(cmdbuf, "ip rule add to %s table %s", pdestip,ptable);
	ms_verbose("%s",cmdbuf);
}

ms_void msiproute_innnerapi_ruleShow(ms_void)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return ;
	}
	ms_system("ip rule show");
}

ms_void msiproute_innerapi_addInfo(IPROUTEContext *piproute_ctt)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	if(0==ms_buflen(piproute_ctt->netmaskbit)
		||0==ms_buflen(piproute_ctt->ifacename)
		||0==ms_buflen(piproute_ctt->ipaddress)
		||0==ms_buflen(piproute_ctt->tablename)
		||0==ms_buflen(piproute_ctt->gateway)){
		return;
	}
	ms_bool is_setdefalut=ms_true;
	ms_bool is_setsrc=ms_true;
	ms_byte cmdbuf[256]={0};
	ms_byte info[1024]={0};
	ms_byte cmd[256]={0};
	ms_sprintfs(cmd,"ip route show table  %s",piproute_ctt->tablename);
	//ms_verbose("cmd:\r\n%s",cmd);
	ms_s32 len=ms_cmdRead(cmd,  info, ms_bufsize(info));
	if(len>0){
		//ms_verbose("info:\r\n%s",info);
		char line[1024]={0};
		ms_ps08 p =info;	
		while(0!=*p){
			msstr_api_getLine(line, ms_bufsize(line), (const char **)&p);
			if(ms_buflen(line)>0){
				//ms_verbose("line:%s",line);
				if(msstr_api_isCasestr(line, "default") !=ms_false){
					char   gateway[msnet_maxlen_gw];
					char   ifacename[msnet_maxlen_ifname];
					sscanf(line, "default via %s dev %s  proto static", (char *)&gateway,(char *)&ifacename);	
					if(	((ms_buflen(piproute_ctt->gateway)>0) && (ms_buflen(gateway)>0) &&ms_strncmp_snaeq(piproute_ctt->gateway, gateway))
							||((ms_buflen(piproute_ctt->ifacename)>0) && (ms_buflen(ifacename)>0) &&ms_strncmp_snaeq(piproute_ctt->ifacename, ifacename))	){
						msiproute_innerapi_tableDel( line,piproute_ctt->tablename);
						//ms_verbose("del;:%s",line);
						is_setdefalut=ms_true;
					}else{
						is_setdefalut=ms_false;
					}
				}else {
					char   netmaskbit[64];
					char   ifacename[msnet_maxlen_ifname];
					sscanf(line, "%s dev %s  proto kernel  scope link", (char *)&netmaskbit,(char *)&ifacename);
					if(((ms_buflen(piproute_ctt->netmaskbit)>0) && (ms_buflen(netmaskbit)>0) &&ms_strncmp_snaeq(piproute_ctt->netmaskbit, netmaskbit))
						||((ms_buflen(piproute_ctt->ifacename)>0) && (ms_buflen(ifacename)>0) &&ms_strncmp_snaeq(piproute_ctt->ifacename, ifacename))){
						msiproute_innerapi_tableDel( line,piproute_ctt->tablename);
						//ms_verbose("del:%s",line);
						is_setsrc=ms_true;
					}else{
						is_setsrc=ms_false;
					}
				}	
			}
		}	
	}
	if(ms_true==is_setsrc){
		//ms_verbose("set");
		msiproute_innerapi_tableAdd(piproute_ctt->tablename, piproute_ctt->ifacename, piproute_ctt->ipaddress, piproute_ctt->netmaskbit);
	}
	if(ms_true==is_setdefalut){
		//ms_verbose("set-default");
		msiproute_innerapi_tableAddDefault(piproute_ctt->tablename, piproute_ctt->ifacename, piproute_ctt->gateway);
	}

	ms_bool is_rule_addfrom=ms_true;
	ms_bool is_rule_addfrom_all=ms_true;
	ms_sprintfs(cmd,"ip rule show | grep %s",piproute_ctt->tablename);
	len=ms_cmdRead(cmd,  info, ms_bufsize(info));
	if(len>0){	//0:	from 192.168.12.6 lookup tab_wlp5s0
		char line[1024]={0};
		ms_ps08 p =info;	
		while(0!=*p){
			msstr_api_getLine(line, ms_bufsize(line), (const char **)&p);
			if(ms_buflen(line)>0){
				ms_s32   ruleid={0};
				char   ipaddress1[64]={0};
				char   tablename[64]={0};
				//ms_debug("%s",line);
				if(msstr_api_isCasestr(line, "from") !=ms_false){
					sscanf(line, "%d:	from %s lookup %s ", (ms_s32 *)&ruleid,(char *)&ipaddress1,(char *)&tablename);
					if(ms_strncmp_saeq(ipaddress1, "all")){
						is_rule_addfrom_all=ms_false;
					}else if (ms_strncmp_saeq(ipaddress1, piproute_ctt->ipaddress)){
						is_rule_addfrom=ms_false;
					}else{
						msiproute_innnerapi_ruleDel_byTableName(piproute_ctt->tablename);
						is_rule_addfrom=ms_true;
					}
				}
			}
		}	
	}
	if(ms_true==is_rule_addfrom){
		msiproute_innnerapi_ruleAdd_bySrc(piproute_ctt->ipaddress, piproute_ctt->tablename);
	}
	if(ms_true==is_rule_addfrom_all){
		//msiproute_innnerapi_ruleAddAll(piproute_ctt->tablename);
	}	
}


ms_void msiproute_innerapi_delInfo(IPROUTEContext *piproute_ctt)
{
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	ms_byte cmdbuf[256]={0};
	ms_byte info[1024]={0};
	ms_byte cmd[256]={0};
	ms_sprintfs(cmd,"ip route show table  %s",piproute_ctt->tablename);
	ms_s32 len=ms_cmdRead(cmd,  info, ms_bufsize(info));
	if(len>0){
		char line[1024]={0};
		ms_ps08 p =info;	
		while(0!=*p){
			msstr_api_getLine(line, ms_bufsize(line), (const char **)&p);
			if(ms_buflen(line)>0){
				msiproute_innerapi_tableDel( line,piproute_ctt->tablename);	
			}
		}	
	}

	ms_sprintfs(cmd,"ip rule show | grep %s",piproute_ctt->tablename);
	len=ms_cmdRead(cmd,  info, ms_bufsize(info));
	if(len>0){	//0:	from 192.168.12.6 lookup tab_wlp5s0
		char line[1024]={0};
		ms_ps08 p =info;	
		while(0!=*p){
			msstr_api_getLine(line, ms_bufsize(line), (const char **)&p);
			if(ms_buflen(line)>0){
				msiproute_innnerapi_ruleDel_byTableName(piproute_ctt->tablename);
			}
		}	
	}	
}

static MSTHREADContext msst_iprouteupdate;
ms_void msiproute_innerapi_updateInfo(ms_void)
{
	msthread_api_setName("iprouteUpdate");
	ms_u08   index=0;
	while(1){
		for(index=0;index<pnetcard_info->num;index++){
			NETCFGInfo *pcfg_info=&pnetcard_info->cfg_info[index];
			IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
			ms_sprintfs(piproute_ctt->tablename,"tab_%s",pcfg_info->name);
			piproute_ctt->tableid=252-index;
			ms_strcpy(piproute_ctt->ifacename,pcfg_info->name);
			if(ms_buflen(pcfg_info->gateway )>0){
				ms_strcpy(piproute_ctt->gateway,pcfg_info->gateway );
			}else{
				ms_strcpy(piproute_ctt->gateway,pcfg_info->usrgateway);
			}
			ms_strcpy(piproute_ctt->netmaskbit,pcfg_info->netmaskbit );
			ms_strcpy(piproute_ctt->ipaddress,pcfg_info->ipaddress);
		}
		for(index=0;index<iproute_info.usrtable_num;index++){
			IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
			msiproute_innerapi_addInfo( piproute_ctt);
		}
#if enable_pppoe_router
		for(index=pnetcard_info->num;index<pnetcard_info->num*2;index++){
			IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
			ms_sprintfs(piproute_ctt->ifacename, "ppp%d", (index-iproute_info.usrtable_num));
			ms_sprintfs(piproute_ctt->tablename,"tab_%s",piproute_ctt->ifacename);
			piproute_ctt->tableid=252-index;
			if(ms_true==ethnppp_ctt.init){
				ms_u08 index=0;
				for(index=0;index<MAXNUM_ETH;index++){
					ETHNInfo *pethn_info=&ethnppp_ctt.ethn_info[index];
					if(ms_strncmp_saeq(piproute_ctt->ifacename, pethn_info->pppoe_param.ethn_name)){
						ms_strcpy(piproute_ctt->ipaddress, pethn_info->ppp_info.ipaddress);
						ms_strcpy(piproute_ctt->netmaskbit, pethn_info->ppp_info.netmask);
						break;
					}
				}
			}
		}
		for(index=pnetcard_info->num;index<pnetcard_info->num*2;index++){
			IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
			msiproute_innerapi_addInfo( piproute_ctt);
		}
#endif		
		ms_sleep(10);
	}
}

ms_bool msiproute_innerapi_writeRouterTableFile(ms_void)
{
	char  strbuf[2048]={0};
	char  strbuf_tmp[2048]={0};	
	ms_strcats(strbuf_tmp, strbuf, "%s",
		"#"LINE_END
		"# reserved values"LINE_END
		"#"LINE_END
		"255	local"LINE_END
		"254	main"LINE_END
		"253	default"LINE_END
		"0	unspec"LINE_END
		"#"LINE_END
		"# local"LINE_END
		"#"LINE_END
		"#1	inr.ruhep"LINE_END	
	);
	ms_u08 index=0;
	for(index=0;index<iproute_info.usrtable_num;index++){
		IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
		ms_strcats(strbuf_tmp, strbuf, "%d	%s"LINE_END,piproute_ctt->tableid,piproute_ctt->tablename);
	}
#if enable_pppoe_router
	for(index=iproute_info.usrtable_num;index<iproute_info.usrtable_num*2;index++){
		IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
		ms_strcats(strbuf_tmp, strbuf, "%d	%s"LINE_END,piproute_ctt->tableid,piproute_ctt->tablename);
	}
#endif	
	if(msmd_api_writeProtect(msiproute_rttables, strbuf, ms_buflen(strbuf))<0){
		ms_errRet(ms_false,"Write %s failed",msiproute_rttables);
	}
	return ms_true;
}
ms_void msiproute_api_webinfo(ms_string ms_out poutbuf,ms_string ms_in minfo,ms_string ms_in mlist_info,ms_string ms_in waitinit_info)
{	
	if(ms_false==msmd_api_isInstallByBin("ip")){
		return;
	}
	ms_byte tempbuf[2048]={0};
	ms_byte info[2048]={0};
	ms_byte rule_info[2048]={0};
	ms_s32 len=0;
	ms_strcats(tempbuf,poutbuf,"<h4 "msiproute_font_style">%s</h4>",minfo) ;
	ms_strcats(tempbuf,poutbuf,"<h4 "msiproute_font_style">%s</h4>",mlist_info) ;
	if(ms_false==iproute_info.init){
		ms_strcats(tempbuf,poutbuf,"<h4 "msiproute_font_style">%s</h4>",waitinit_info) ;
	}else{
		ms_debug("cmd:%s","ip rule show");
		len=ms_cmdRead("ip rule show",  rule_info, ms_bufsize(rule_info));
		if(len>0){	
			char line[1024]={0};
			char line_num=0;
			ms_ps08 p =rule_info;
			ms_strcats(tempbuf,poutbuf,"<ul "msiproute_font_style">");
			while(0!=*p){
				msstr_api_getLine(line, ms_bufsize(line), (const char **)&p);
				if(ms_buflen(line)>0){
					ms_strcats(tempbuf,poutbuf,"<li>%03d.%s</li>&nbsp;&nbsp;&nbsp;",(++line_num),line) ;
				}
			}
			ms_strcats(tempbuf,poutbuf,"</ul>");
		}

		ms_u08 index=0;
		for(index=0;index<iproute_info.table_num;index++){
			IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
			ms_byte cmd[256]={0};
			if(ms_false==msstr_api_isCasestr(rule_info, piproute_ctt->tablename)){
				//ms_debug("rule_info:%s\r\n,tablename:%s",rule_info, piproute_ctt->tablename);
				continue;
			}
			ms_strcats(tempbuf,poutbuf,"<h2 "msiproute_font_style">%03d.TABLE(%s)-INFO</h2>",(index+1),piproute_ctt->tablename) ;
			ms_sprintfs(cmd,"ip route show table  %s",piproute_ctt->tablename);
			ms_debug("cmd:%s",cmd);
			ms_s32 len=ms_cmdRead(cmd,  info, ms_bufsize(info));
			if(len>0){
				//ms_verbose("info:\r\n%s",info);
				char line[1024]={0};
				char line_num=0;
				ms_ps08 p =info;	
				ms_strcats(tempbuf,poutbuf,"<ul "msiproute_font_style">")
				while(0!=*p){
					msstr_api_getLine(line, ms_bufsize(line), (const char **)&p);
					if(ms_buflen(line)>0){
						ms_strcats(tempbuf,poutbuf,"<li>%03d.%s</li>&nbsp;&nbsp;&nbsp;",(++line_num),line) ;
					}
				}
				ms_strcats(tempbuf,poutbuf,"</ul>");
			}
		}
	}
	ms_strcats(tempbuf,poutbuf,	
			"</tbody>"
		);			
	ms_strcats(tempbuf,poutbuf,	
		"</table>"
		);

	
}
ms_bool msiproute_api_init(ms_bool enable)
{
	if(ms_true==iproute_info.init){
		return ms_true;
	}
	
	ms_memset0(&iproute_info, ms_bufsize(IPROUTEContext));
	
	iproute_info.enable=enable;
	if(ms_false==iproute_info.enable){
		return ms_true;
	}
	
	if(ms_false==pnetcard_info->isinit){
		ms_errRet(ms_false,"%s","Init pnetcard_info first");
	}
	
	msiproute_innerapi_IPVersion();
	
	iproute_info.usrtable_num=pnetcard_info->num;
	iproute_info.table_num=iproute_info.usrtable_num+3;
	ms_u08   index=0;
	NETCFGInfo *pcfg_info=ms_null;
	for(index=0;index<iproute_info.usrtable_num;index++){
		pcfg_info=&pnetcard_info->cfg_info[index];
		IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
		ms_sprintfs(piproute_ctt->tablename,"tab_%s",pcfg_info->name);
		piproute_ctt->tableid=252-index;
		ms_strcpy(piproute_ctt->ifacename,pcfg_info->name);
		if(ms_buflen(pcfg_info->gateway )>0){
			ms_strcpy(piproute_ctt->gateway,pcfg_info->gateway );
		}else{
			ms_strcpy(piproute_ctt->gateway,pcfg_info->usrgateway);
		}
		ms_strcpy(piproute_ctt->netmaskbit,pcfg_info->netmaskbit );
		ms_strcpy(piproute_ctt->ipaddress,pcfg_info->ipaddress);
		msiproute_innerapi_delInfo( piproute_ctt);
	}
#if enable_pppoe_router
	for(index=iproute_info.usrtable_num;index<iproute_info.usrtable_num*2;index++){
		IPROUTEContext *piproute_ctt=&iproute_info.iproute_ctt[index];
		ms_sprintfs(piproute_ctt->ifacename, "ppp%d", (index-iproute_info.usrtable_num));
		ms_sprintfs(piproute_ctt->tablename,"tab_%s",piproute_ctt->ifacename);
		piproute_ctt->tableid=252-index;
		if(ms_true==ethnppp_ctt.init){
			ms_u08 index=0;
			for(index=0;index<MAXNUM_ETH;index++){
				ETHNInfo *pethn_info=&ethnppp_ctt.ethn_info[index];
				if(ms_strncmp_saeq(piproute_ctt->ifacename, pethn_info->pppoe_param.ethn_name)){
					ms_strcpy(piproute_ctt->ipaddress, pethn_info->ppp_info.ipaddress);
					ms_strcpy(piproute_ctt->netmaskbit, pethn_info->ppp_info.netmask);
					break;
				}
			}
		}
		msiproute_innerapi_delInfo( piproute_ctt);
	}
#endif	
	ms_sprintfs(iproute_info.iproute_ctt[pnetcard_info->num].tablename,"%s","local");
	ms_sprintfs(iproute_info.iproute_ctt[pnetcard_info->num+1].tablename,"%s","main");
	ms_sprintfs(iproute_info.iproute_ctt[pnetcard_info->num+2].tablename,"%s","default");
	
	if(ms_true==iproute_info.enable){
		msiproute_innerapi_writeRouterTableFile();
		msthread_api_create(&msst_iprouteupdate,    "msiproute_update", msiproute_innerapi_updateInfo, (ms_void *) ms_null);
	}
	iproute_info.init=ms_true;
	return ms_true;
}

ms_void msiproute_api_deinit(ms_void)
{
	if(ms_false==iproute_info.init){
		return;
	}
	if(ms_true==iproute_info.enable){
		msthread_api_destroy(&msst_iprouteupdate);
	}
}
#undef MSIPROUTE_C
